package edu.stanford.prpl.facade.templates;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import org.xmlpull.v1.XmlPullParser;

import edu.stanford.prpl.facade.UIEngine.devicePlatform;


public abstract class UITemplate 
{
    public devicePlatform selectedPlatform = devicePlatform.WEB;
    public String templateTagName = null;
    public String dataObjectName = null;

    public UITemplate(String tagName, devicePlatform dP)
    { 
        this.templateTagName = tagName;
        this.selectedPlatform = dP;
    }
    
    public void parseTemplate(XmlPullParser xpp) throws Exception
    {
        // String name = xpp.getName();
        int correspondingDepthLevel = xpp.getDepth(); // sanity check
                
        try
        {        
                int eventType = xpp.next();
                do 
                {
                    if(eventType == XmlPullParser.START_TAG) 
                    {
                        processTemplateStartElement(xpp);
                    }
                    else if(eventType == XmlPullParser.END_TAG) 
                    {
                        processTemplateEndElement(xpp);
                        if (correspondingDepthLevel == xpp.getDepth())
                        {
                            if (this.templateTagName.equals(xpp.getName()))
                               break;
                            else
                               throw new Exception("Missing Closing tag for <"+this.templateTagName+" dataObjectName=\""+this.dataObjectName+"\" ...> (Depth Level="+correspondingDepthLevel+")");
                        }
                    }
                    
                    eventType = xpp.next();
                } 
                while (eventType != XmlPullParser.END_DOCUMENT);
        }
        catch(Exception e)
        {
                // Error
                System.out.println("Exception e: " + e.toString());
                throw e;
                // return;
        }
    }

    protected abstract void processTemplateStartElement (XmlPullParser xpp) throws Exception;
    protected void processTemplateEndElement (XmlPullParser xpp) throws Exception
    {
        String name = xpp.getName();
        String uri = xpp.getNamespace();
        //if ("".equals (uri))
        //    System.out.println("End element: " + name);
        //else
        //    System.out.println("End element:   {" + uri + "}" + name);
    }

    
    // Invariants:
    // (a) On entering parseData() method, XML parser cursor should be 
    //     located at the opening tag of the XML data fragment for the 
    //     UI template object currently being processed
    // (b) On returning from the parseData() call successfully, XML parser
    //     cursor should be located at the closing tag of the XML data fragment
    public void parseData(XmlPullParser xpp, UIModelData currentUIData) throws Exception
    {
        String thisDataTagName = xpp.getName();
        int thisDataDepthLevel = xpp.getDepth(); // sanity check
        
        // System.out.println("Now processing tag <"+thisDataTagName+"> at depth level "+thisDataDepthLevel);

        try
        {
                // Get attributes for current UI widget being processed
                xpp.require(XmlPullParser.START_TAG, null, null);
                if (thisDataTagName.equals(this.dataObjectName))
                {
                    String attrName, attrValue;                    
                    int numAttributes = xpp.getAttributeCount();
                    for (int i = 0; i < numAttributes; i++)
                    {
                        attrName  = xpp.getAttributeName(i);
                        attrValue = xpp.getAttributeValue(i);                        
                        if (attrName.length() > 0) {
                            currentUIData.attributesStore.put(attrName, attrValue);
                            System.out.println("\tAdded attribute "+attrName+"="+attrValue);
                        }
                    }
                    xpp.next();
                }             
                
                int eventType = xpp.getEventType();
                do 
                {
                    if(eventType == XmlPullParser.START_TAG) 
                    {
                        processDataStartElement(xpp, currentUIData);
                    }
                    else if(eventType == XmlPullParser.END_TAG) 
                    {
                        processDataEndElement(xpp);
                    }
                    
                    // Encountered correct matching closing tag to the tag 
                    // when program execution first entered this method
                    if (thisDataDepthLevel == xpp.getDepth())
                    {
                        if (thisDataTagName.equals(xpp.getName()) && xpp.getEventType() == XmlPullParser.END_TAG)
                           break;
                        // else
                        // throw new Exception("Missing Closing tag for <"+this.templateTagName+" dataObjectName=\""+this.dataObjectName+"\" ...> (Depth Level="+this.correspondingDepthLevel+")");
                    }                  
                    
                    eventType = xpp.next();
                } 
                while (eventType != XmlPullParser.END_DOCUMENT);
        }
        catch(Exception e)
        {
                // Error
                System.out.println("Exception e: " + e.toString());
                throw e;
                // return;
        }
    }    

    protected abstract void processDataStartElement (XmlPullParser xpp, UIModelData currentUIData) throws Exception;
    protected void processDataEndElement (XmlPullParser xpp) throws Exception
    {
        String name = xpp.getName();
        String uri = xpp.getNamespace();
        //if ("".equals (uri))
        //    System.out.println("End element: " + name);
        //else
        //    System.out.println("End element:   {" + uri + "}" + name);
    }    
    
    
    public abstract void generateUI(UIModelData currentUIData, Object platformData);
    public void generateUIFragment(UIModelData currentUIData, Object platformData)
    {
        generateUI(currentUIData, platformData);
    }
}